<!DOCTYPE html>
<title>Verify properties of the drag and drop events</title>
<style>
#source {
    padding: 5pt;
    border: 3px solid #00cc00;
    background: #00cccc;
    width: 80px;
    height: 80px;
}
#target {
    padding: 5pt;
    border: 3px solid #0000cc;
    background: #cc00cc;
    width: 80px;
    height: 80px;
}
</style>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<div id="source" draggable="true"></div>
<br>
<div id="target"></div>
<p>To test manually:</p>
<ol>
  <li>Start dragging the cyan box.
  <li>Drag over the magenta box (without dropping).</li>
  <li>Drag away from the magenta box (without dropping).</li>
  <li>Drag back over the magenta box and drop.</li>
</ol>
<script>
if (!window.eventSender)
  setup({explicit_timeout: true});

promise_test(function() {
  const source = document.getElementById("source");
  const target = document.getElementById("target");

  const events = [
    {type: 'dragstart', cancelable: true, bubbles: true},
    {type: 'drag', cancelable: true, bubbles: true},
    {type: 'dragend', cancelable: false, bubbles: true},

    {type: 'dragenter', cancelable: true, bubbles: true},
    {type: 'dragover', cancelable: true, bubbles: true},
    {type: 'dragleave', cancelable: false, bubbles: true},
    {type: 'drop', cancelable: true, bubbles: true},
  ];

  let resolve;
  const wait_for_all_events = new Promise(r => { resolve = r; })
  const map = new Map();

  function record(event) {
    map.set(event.type, event);
    if (map.size === events.length)
      resolve();
  }

  function record_and_cancel(event) {
    event.preventDefault();
    record(event);
  }

  source.ondragstart = record;
  source.ondrag = record;
  source.ondragend = record;

  target.ondragenter = record_and_cancel;
  target.ondragover = record_and_cancel;
  target.ondragleave = record;
  target.ondrop = record;

  if (window.eventSender) {
    const dragStartX = source.offsetLeft + 5;
    const dragStartY = source.offsetTop + 5;
    const dragEndX = target.offsetLeft + 5;
    const dragEndY = target.offsetTop + 5;

    // Start at the source.
    eventSender.mouseMoveTo(dragStartX, dragStartY);
    eventSender.mouseDown();
    // Drag over the target.
    eventSender.mouseMoveTo(dragEndX, dragEndY);
    // Leave the target, back to the source.
    eventSender.mouseMoveTo(dragStartX, dragStartY);
    // Then drop on the target.
    eventSender.mouseMoveTo(dragEndX, dragEndY);
    eventSender.mouseUp();
  }

  return wait_for_all_events.then(() => {
    for (const event of events) {
      assert_equals(
        map.get(event.type).cancelable, event.cancelable,
        event.type + ' ' + (event.cancelable ? 'should' : 'should not') +
        ' be cancelable');

      assert_equals(
        map.get(event.type).bubbles, event.bubbles,
        event.type + ' ' +
        (event.cancelable ? 'should' : 'should not') + ' bubble');
    }
  });

}, 'Test that drag and drop events have expected initial properties');
</script>
